//
//  terminalControl.m
//  serialTest
//
//  Created by mt-007 on 2021/3/20.
//

#import "terminalControl.h"
#import "devSearch.h"
#import "serial.h"
#import "checkInput.h"
#import "buildInCommand.h"
#import "printReadBuff.h"

@implementation terminalControl

//@synthesize systemVariable;

/**
 * @return the menu code, 0 is success done. else is something wrong.
 * @brief start the program, config and run serial port, link the orther code file.
 * This function will running 3 mode from self class.
 * 1. choose device
 * 2. open and config device.
 * 3. run
*/
- (int)mainMenu {
    // choose device
    serial *mySerial = [serial alloc];
    [self chooseDevice];
    int fd = [mySerial serialOpen:comNameFromDEV];
    if (fd == -1) {
        NSLog(@"feiled, will go to the main menu");
        return (-1);
    }
    
    // open device and config it.
    mySerial = [self openDevice:mySerial andFileDirection:fd];
    
    // running the program
    [self running:mySerial andFileDirection:fd];
    
    return 0;
}

/**
 * @brief get device name from /dev/ and choose device.
 */
-(void)chooseDevice {
    // get the deveice name from /dev/
    NSDictionary *deviceFilesDic = [devSearch searchDevice:@"/dev/"];
    
    NSArray *arr = [deviceFilesDic allKeys];
    
    NSLog(@"Now we can find those device.");
    for(NSInteger i = 0; i < arr.count; i++) {
        NSLog(@"%@ : %@",arr[i], [deviceFilesDic objectForKey:arr[i]]);
    }
    
    // select the device
    int inputSelect = 0;
    NSString *preName = @"device";
    NSLog(@"plz input the device number [1~n]");
    
    while (scanf("%d", &inputSelect)) {
        if(inputSelect >= 1 && inputSelect <= arr.count){
            break;
        }
        NSLog(@"input error, plz input again.(You ought to input more than 1 but less than device number)");
    }
    getchar();
    
    // connect device
    NSMutableString *deviceSelect = [[NSMutableString alloc] initWithString:preName];
    [deviceSelect appendString:[NSString stringWithFormat:@"%d", inputSelect]];
    
    comNameFromDEV = [deviceFilesDic[deviceSelect] mutableCopy];
    NSLog(@"choose %@", comNameFromDEV);
}


/**
 * @param mySerial Instantiated serial port module
 * @param fd Opened file number pointing to the serial port.
 *
 * @return After config serial port module.
 *
 * @brief open and config device.
 */
- (serial *)openDevice:(serial *)mySerial andFileDirection:(int)fd {
    //setting config, default value is 11520 8 'N' 1
    int inputBaudRate = 230400;
    int inputDataBit = 8;
    char inputCheckParity = 'N';
    int inputStopBit = 1;
    
    NSLog(@"plz input the (int)BaudRate  (int)DataBit  (char)CheckParity  (int)StopBit");
    NSLog(@"If you input error, it can not work as normal as well.");
    NSLog(@"So, use default?(Y/N)");
    
    char useDefault;
    checkInput *check = [[checkInput alloc] init];
    // make sure the value is right.
    while(scanf("%c", &useDefault)){
        getchar();
        if(useDefault == 'N' || useDefault == 'n') {
            NSLog(@"choose input.");
            while(scanf("%d %d %c %d", &inputBaudRate, &inputDataBit, &inputCheckParity, &inputStopBit)){
                inputCheckParity = [self upperCharacter:inputCheckParity];
                BOOL isRight = [check
                                checkConfigInputRight:inputBaudRate
                                           andDataBit:inputDataBit
                                       andCheckParity:inputCheckParity
                                           andStopBit:inputStopBit];
                if(isRight){
                    NSLog(@"input successful. code %d", isRight);
                    break;
                }
                NSLog(@"input again.");
            }
            break;
        } else if(useDefault == 'Y' || useDefault == 'y') {
            NSLog(@"chose default.");
            NSLog(@"BaudRate is %d\tDataBit is %d\tCheckParity is %c\tStopBit is %d", inputBaudRate, inputDataBit, inputCheckParity, inputStopBit);
            break;
        }
        NSLog(@"input error, plz input again.");
    }
    // configural serial port
    [mySerial serialConfig:fd andBaudRate:inputBaudRate andDataBit:inputDataBit andCheckParity:inputCheckParity andStopBit:inputStopBit];
    return mySerial;
}

/**
 * Convert lowercase letters to uppercase ones
 */
- (char)upperCharacter:(char)ch{
    if(ch >= 'a' && ch <= 'z'){
        ch -= 32;
    }
    return ch;
}

/**
 * @param mySerial Instantiated serial port module
 * @param fd Opened file number pointing to the serial port.
 *
 * @brief The main interactive module, where the specific communication of the serial port
 */
- (void)running:(serial *)mySerial andFileDirection:(int)fd {
    // running the main menu - now we can use console to data transmission.
    size_t readBuffLength = 1024;
    size_t writeBuffLength = 1024;
    
    char readBuff[readBuffLength];
    char writeBuff[writeBuffLength];
    
    int flagCommand;
    char systemVar = 'c';
    
    printf("----------BEGIN---------\n");
    while (scanf("%s", writeBuff)) {
        
        // use class builtInCommand to answer build-in command.
        // flagCommand - 0 is mean done
        // flagCommand - -1 is mean build-in command and should skip the loop once.
        // flagCommand - 1 is mean no build-in command and just run the next.
        flagCommand = [buildInCommand command:[NSString stringWithUTF8String:writeBuff] andSystemVar:&systemVar];
        if(flagCommand == 0){
            break;
        }else if(flagCommand == -1){
            continue;
        }
        
        //mix writeBuff with \r\n\0
        strcat(writeBuff,"\r\n\0");
        
        // get the writeBuff length, should i encapsulate a function to get this?
        writeBuffLength = strlen(writeBuff);
        
        // write data to serial port.
        len_w = [mySerial serialWrite:fd andBuff:writeBuff andBuffLength:writeBuffLength];
        
        // throw the test, the minimum response time must be 1 second.(0.99 will not work).
        sleep(1);
        
        // read data from serial port.
        len_r = [mySerial serialRead:fd andBuff:readBuff andBuffLength:readBuffLength];
        
        // print read data.
        //[self printReadBuff:readBuff :len_r];
        [printReadBuff print:readBuff andLength:len_r andMode:systemVar];
    }
    printf("-----------END----------\n");
}

/**
 * print the read data, the interesting thing is, there exist not '\0' to finish, however it use '\r''\n' to finish.
 * so we need manual program this print function and do not use printf() or NSlog()
 *
 * Update:
 *      remove - use class printReadBuff to control print.
 */
- (void)printReadBuff :(char *)readBuff :(ssize_t)length {
    for(int i = 0; i < length; i++){
        printf("%c", readBuff[i]);
    }
}

@end
